home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / TurboTCP 1.0.1 / TurboTCP.source / CTCPStream.cp < prev    next >
Text File  |  1993-12-10  |  41KB  |  1,723 lines

  1. /*
  2. ** CTCPStream.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP stream class
  6. **
  7. **    Copyright © 1993, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11.  
  12. #include "CTCPStream.h"
  13.  
  14. #ifndef TurboTCPHeaders
  15.     #include <TCLUtilities.h>
  16.     #include <CList.h>
  17.     #include "TurboTCP.const.h"
  18. #endif
  19.  
  20. #include "CTCPAsyncCall.h"
  21. #include "CTCPDriver.h"
  22.  
  23.  
  24. //    —— initialize/destroy stream ——
  25.  
  26. /*______________________________________________________________________
  27. **
  28. ** ITCPStream
  29. **
  30. **    Create a new TCP stream. Allocates the receive buffer (if there’s enough memory).
  31. **
  32. **    The stream can be configured to automatically receive data. If auto-receive is used,
  33. **    the stream object will automatically issue TCPNoCopyRcv calls as needed and respond to
  34. **    completion notifications when data arrives; data will be returned by the HandleDataArrived
  35. **    method or by the receive bypass procedure (see InstallRcvBypassProc).
  36. **
  37. **    If auto-receive is used, you should not send NoCopyRcv and Rcv messages to this stream.
  38. **    They may conflict with the auto-receive calls. Auto-receive cannot be turned on or off
  39. **    once the stream object is created.
  40. **
  41. **        recBufferSize (long):            size of the receive buffer we need; use 0 or
  42. **                                        less then 4K to get the minimum 4K buffer
  43. **        autoReceiveSize (short):            number of entries in RDS for auto-receive,
  44. **                                        0 to disable autoreceiving
  45. **        autoReceiveNum (short):            number of auto-receive calls to issue at once
  46. **                                        must be at least 1
  47. **
  48. */
  49.  
  50. void CTCPStream::ITCPStream (long recBufferSize, short autoReceiveSize, short autoReceiveNum)
  51.  
  52. {
  53.  
  54.     // clear all of our variables
  55.     
  56.     macTCPStream = NULL;
  57.     itsBuffer = NULL;
  58.     itsAsyncCalls = NULL;    
  59.     hasSessionOpen = pendingOpen = pendingClose = remoteClose
  60.         = pendingAbort = pendingNotify = pendingDispose = FALSE;
  61.     
  62.     itsBufferSize = 0L;
  63.     rcvUrgent = FALSE;
  64.     itsRcvBypassProc = NULL;
  65.     itsRcvBypassTarget = NULL;
  66.     
  67.     itsULPtimeout = 0;
  68.     itsULPaction = 0;
  69.     itsValidityFlag = 0;
  70.     itsCommandTimeoutValue = 0;
  71.     itsTosFlags = 0;
  72.     itsPrecedence = 0;
  73.     itsDontFrag = 0;
  74.     itsTimeToLive = 0;
  75.     itsSecurity = 0;
  76.     itsOptionCnt = 0;
  77.     sendNextUrgent = 0;
  78.     sendNextPush = FALSE;
  79.  
  80.     notifClosing = FALSE;
  81.     notifTimeout = FALSE;
  82.     notifTerminate = FALSE;
  83.     notifDataArrived = FALSE;
  84.     notifUrgent = FALSE;
  85.     notifICMP = FALSE;
  86.     disposeOnTerminate = FALSE;
  87.     receivedClose = FALSE;
  88.     receivedTerminate = FALSE;
  89.     itsAutoReceiveSize = Min(autoReceiveSize, autoReceiveMax);
  90.     itsAutoReceiveNum = Max(autoReceiveNum, 1);
  91.  
  92.  
  93.     // prepare the async events queues
  94.     
  95.     qNotifyEntry.qType = notifyStream;
  96.     qNotifyEntry.qSelfLink = this;
  97.     qDisposeEntry.qType = disposeStream;
  98.     qDisposeEntry.qSelfLink = this;
  99.  
  100.  
  101.     // initialize the collaborator object
  102.     
  103.     CCollaborator::ICollaborator();
  104.  
  105.  
  106.     // create the async calls list
  107.     
  108.     itsAsyncCalls = new (CCluster);
  109.     itsAsyncCalls->ICluster();
  110.  
  111.  
  112.     // create the receive buffer
  113.     
  114.     if (recBufferSize < minReceiveSize)                    // if caller requested a buffer that is too small,
  115.         recBufferSize = minReceiveSize;                //    beef it up to acceptable size (4K)
  116.     itsBuffer = NewHandle(recBufferSize);
  117.     FailNIL(itsBuffer);
  118.     itsBufferSize = recBufferSize;
  119.  
  120.  
  121.     /*
  122.     ** Don’t create TCP stream here. Therefore, if a session is never opened and the program
  123.     ** crashes (or ExitToShell is used by the programmer), MacTCP will remain stable.
  124.     */
  125.     
  126. }
  127.  
  128.  
  129. /*______________________________________________________________________
  130. **
  131. ** Dispose
  132. **
  133. **    Get rid of a TCP stream. Deallocates the receive buffer. If a session is still open,
  134. **    issues an Abort command, then postpones its disposal so completion routines still
  135. **    have a valid object to call.
  136. **
  137. */
  138.  
  139. void CTCPStream::Dispose (void)
  140.  
  141. {
  142.     TCPiopb theReleaseParam;
  143.  
  144.  
  145.     // we’re no longer in delayed disposal queue
  146.  
  147.     pendingDispose = FALSE;
  148.  
  149.  
  150.     // initiate a graceful close if necessary
  151.     
  152.     if (hasSessionOpen && !receivedClose) {
  153.         Close();
  154.         disposeOnTerminate = TRUE;
  155.         return;
  156.     }
  157.  
  158.  
  159.     // abort any connections that are yet to open
  160.     
  161.     if (pendingOpen) {
  162.         Abort();
  163.         disposeOnTerminate = TRUE;
  164.         return;
  165.     }
  166.  
  167.  
  168.     // if calls are still outstanding, wait a while
  169.     
  170.     if (!itsAsyncCalls->IsEmpty()) {
  171.         if ((macTCPStream) && pendingOpen) {                // get rid of the thing…
  172.             Abort();
  173.             PostponeDispose();
  174.             return;
  175.         }
  176.         if ((macTCPStream) && pendingOpen)
  177.             DoSyncCall(TCPRelease, &theReleaseParam);        // perhaps this will shake it loose
  178.         PostponeDispose();
  179.         return;
  180.     }
  181.  
  182.  
  183.     // if connection is still there, release stream to see if that shakes things loose
  184.     
  185.     if (macTCPStream && hasSessionOpen && !receivedTerminate) {
  186.         DoSyncCall(TCPRelease, &theReleaseParam);
  187.         macTCPStream = NULL;
  188.         PostponeDispose();
  189.         return;        
  190.     }
  191.  
  192.  
  193.     // make sure that terminate notice has been received
  194.     
  195.     if (hasSessionOpen && !receivedTerminate) {
  196.         PostponeDispose();
  197.         return;
  198.     }    
  199.  
  200.  
  201.     // release the stream from MacTCP
  202.     
  203.     if (macTCPStream)
  204.         DoSyncCall(TCPRelease, &theReleaseParam);
  205.     gTCPDriver->RemoveActiveStream(this);
  206.  
  207.  
  208.     // forget the async calls list
  209.     
  210.     ForgetObject(itsAsyncCalls);
  211.  
  212.  
  213.     // release the receive buffer
  214.     
  215.     ForgetHandle(itsBuffer);
  216.     macTCPStream = NULL;
  217.     itsBufferSize = 0L;
  218.  
  219.     CCollaborator::Dispose();
  220. }
  221.  
  222.  
  223. /*______________________________________________________________________
  224. **
  225. ** OwnerDied
  226. **
  227. **    Called when stream’s owner is being disposed and no longer wishes to receive
  228. **    notifications.
  229. **
  230. */
  231.  
  232. void CTCPStream::OwnerDied (void)
  233.  
  234. {
  235.     InstallRcvBypass(NULL, NULL);
  236. }
  237.  
  238.  
  239. //    —— basic user TCP calls ——
  240.  
  241. /*______________________________________________________________________
  242. **
  243. ** OpenConnection
  244. **
  245. **    Opens a TCP session (either passive or active). Note that MacTCP seems to fail when
  246. **    non-zero values are used for theRemoteIP and theRemotePort.
  247. **
  248. **        passive (Boolean):        TRUE for passive open; FALSE for active open
  249. **        theRemoteIP (ip_addr):    IP address of remote host (0 for any host)
  250. **        theRemotePort (b_16):    TCP port of remote host (0 for any port)
  251. **        theLocalPort (b_16):        TCP port for local host (0 for any port)
  252. **
  253. */
  254.  
  255. void CTCPStream::OpenConnection (Boolean passive, ip_addr theRemoteIP,
  256.                             b_16 theRemotePort, b_16 theLocalPort)
  257.  
  258. {
  259.     TCPiopb    theCreateParam;
  260.     TCPiopb    theOpenParam;
  261.     OSErr    theResult;
  262.  
  263.     
  264.     // ensure that MacTCP is awake & ready for us
  265.     
  266.     if (!(gTCPDriver->CheckTCPDriver()))
  267.         FailOSErr(noTCPError);
  268.  
  269.  
  270.     // if the stream hasn’t been created yet, create one now
  271.     
  272.     if (!macTCPStream) {
  273.         MoveHHi(itsBuffer);                            // lock the receive buffer
  274.         HLock(itsBuffer);
  275.         
  276.         MoveHHi((Handle) this);                        // prevent ASR calls while Memory Manager
  277.         this->Lock(TRUE);                            //    is moving this object
  278.         
  279.         theCreateParam.csParam.create.rcvBuff = *itsBuffer;
  280.         theCreateParam.csParam.create.rcvBuffLen = itsBufferSize;
  281.         theCreateParam.csParam.create.notifyProc = &NotifyProc;
  282.         theCreateParam.csParam.create.userDataPtr = (Ptr) this;
  283.         
  284.         macTCPStream = (Ptr) 1;                        // preempt the check for no stream present
  285.         theResult = DoSyncCall(TCPCreate, &theCreateParam);
  286.         
  287.         if (theResult == noErr) {                        // did we get a valid stream?
  288.             gTCPDriver->RegisterActiveStream(this);    //    yes, register in global stream list
  289.             macTCPStream = (Ptr) theCreateParam.tcpStream;
  290.         } else {
  291.             macTCPStream = NULL;
  292.             HandleOpenFailed(theResult);
  293.         }
  294.     }
  295.  
  296.  
  297.     // don’t allow open if already opening
  298.     
  299.     if (!(hasSessionOpen || pendingOpen)) {
  300.  
  301.         // fill in parms to open call
  302.         
  303.         theOpenParam.csParam.open.ulpTimeoutValue = itsULPtimeout;
  304.         theOpenParam.csParam.open.ulpTimeoutAction = itsULPaction;
  305.         theOpenParam.csParam.open.validityFlags = itsValidityFlag;
  306.         theOpenParam.csParam.open.commandTimeoutValue = itsCommandTimeoutValue;
  307.         theOpenParam.csParam.open.remoteHost = theRemoteIP;
  308.         theOpenParam.csParam.open.remotePort = theRemotePort;
  309.         theOpenParam.csParam.open.localPort = theLocalPort;
  310.         theOpenParam.csParam.open.tosFlags = itsTosFlags;
  311.         theOpenParam.csParam.open.precedence = itsPrecedence;
  312.         theOpenParam.csParam.open.dontFrag = itsDontFrag;
  313.         theOpenParam.csParam.open.timeToLive = itsTimeToLive;
  314.         theOpenParam.csParam.open.security = itsSecurity;
  315.         theOpenParam.csParam.open.optionCnt = itsOptionCnt;
  316.         BlockMove(&itsOptions, &theOpenParam.csParam.open.options, 40);
  317.         theOpenParam.csParam.open.userDataPtr = (Ptr) this;
  318.         pendingOpen = TRUE;
  319.         receivedClose = receivedTerminate = FALSE;
  320.     
  321.         // perform the call
  322.         
  323.         theResult = DoAsyncCall((passive ? TCPPassiveOpen : TCPActiveOpen),
  324.                             &theOpenParam);
  325.         if (theResult)
  326.             HandleOpenFailed(theResult);
  327.         
  328.         // pull IP address/port info from remote host
  329.         
  330.         itsRemoteIP = theOpenParam.csParam.open.remoteHost;
  331.         itsRemotePort = theOpenParam.csParam.open.remotePort;
  332.         itsLocalIP = theOpenParam.csParam.open.localHost;
  333.         itsLocalPort = theOpenParam.csParam.open.localPort;
  334.     }
  335.     else
  336.         HandleOpenFailed(connectionExists);
  337.     
  338. }
  339.  
  340.  
  341. /*______________________________________________________________________
  342. **
  343. ** Close
  344. **
  345. **    Signal that the connection should be closed. The stream’s owner should wait until it
  346. **    receives the tcpStreamClosed message before disposing of the stream object.
  347. **    This will allow time for the host to close gracefully.
  348. **
  349. */
  350.  
  351. void CTCPStream::Close (void)
  352.  
  353. {
  354.     TCPiopb    theCloseParam;
  355.     OSErr    theResult;
  356.  
  357.         if ((hasSessionOpen && (!pendingAbort) && (!pendingClose)) || remoteClose) {
  358.         pendingClose = TRUE;
  359.         pendingOpen = remoteClose = FALSE;
  360.         theCloseParam.csParam.close.ulpTimeoutValue = itsULPtimeout;
  361.         theCloseParam.csParam.close.ulpTimeoutAction = itsULPaction;
  362.         theCloseParam.csParam.close.validityFlags = itsValidityFlag;
  363.         theCloseParam.csParam.close.userDataPtr = (Ptr) this;
  364.         theResult = DoAsyncCall(TCPClose, &theCloseParam);
  365.         if ((theResult != noErr) && (theResult != connectionDoesntExist))
  366.             HandleTCPError(theResult, TCPClose);
  367.     }
  368. }
  369.  
  370.  
  371. /*______________________________________________________________________
  372. **
  373. ** Abort
  374. **
  375. **    Cancel the connection immediately. This call is performed synchronously. USE THIS CALL
  376. **    WITH CAUTION! MacTCP seems to get quite confused when a session is closed and
  377. **    data hasn’t all been received.
  378. **
  379. */
  380.  
  381. void CTCPStream::Abort (void)
  382.  
  383. {
  384.     TCPiopb    theAbortParam;
  385.     OSErr    theResult;
  386.  
  387.     if ((hasSessionOpen || pendingOpen) && (!pendingAbort)) {
  388.         pendingAbort = TRUE;
  389.         pendingOpen = pendingClose = remoteClose = FALSE;
  390.         theAbortParam.csParam.abort.userDataPtr = (Ptr) this;
  391.         theResult = DoSyncCall(TCPAbort, &theAbortParam);
  392.         if (theResult)
  393.             HandleTCPError(theResult, TCPAbort);
  394.         else
  395.             receivedClose = TRUE;
  396.     }
  397. }
  398.  
  399.  
  400. /*______________________________________________________________________
  401. **
  402. ** NoCopyRcv
  403. **
  404. **    Receive data without copying from TCP’s internal buffers. The completion routine in
  405. **    CTCPAsyncCall will take care of returning the RDS automatically. IF YOU ARE USING
  406. **    AUTO-RECEIVE, DO NOT CALL THIS METHOD!
  407. **
  408. **        itsRDS (rdsEntry *):        receive data structure (see MacTCP manual, p30)
  409. **        itsRDSSize (b_16):        number of entries in RDS (6 bytes each)
  410. **        itsTimeOut (b_16):        command timeout value in seconds (0 = infinite)
  411. **
  412. */
  413.  
  414. void CTCPStream::NoCopyRcv (rdsEntry *itsRDS, b_16 itsRDSSize, b_16 itsTimeOut)
  415.  
  416. {
  417.     TCPiopb    theRcvParam;
  418.     OSErr    theResult;
  419.  
  420.     theRcvParam.csParam.receive.commandTimeoutValue = itsTimeOut;
  421.     theRcvParam.csParam.receive.rdsPtr = (Ptr) itsRDS;
  422.     theRcvParam.csParam.receive.rdsLength = (unsigned short) Min(itsRDSSize, autoReceiveMax);
  423.     theRcvParam.csParam.receive.userDataPtr = (Ptr) this;
  424.     theRcvParam.csParam.open.options[36] = (Byte) itsAutoReceiveSize;
  425.  
  426.     theResult = DoAsyncCall(TCPNoCopyRcv, &theRcvParam);
  427.     if ((theResult != noErr) && (theResult != connectionClosing))
  428.         HandleTCPError(theResult, TCPNoCopyRcv);
  429.  
  430. }
  431.  
  432.  
  433. /*______________________________________________________________________
  434. **
  435. ** BfrReturn
  436. **
  437. **    Return a receive buffer to MacTCP used by the NoCopyRcv method. You should never need
  438. **    to call this method, since it is done automatically by the CTCPAsyncCall::Dispatch()
  439. **    method which handles all asynchronous completions.
  440. **
  441. **        itsRDS (Ptr):    the RDS structure to return
  442. **
  443. */
  444.  
  445. void CTCPStream::BfrReturn (Ptr itsRDS)
  446.  
  447. {
  448.     TCPiopb    theRcvParam;
  449.     OSErr    theResult;
  450.  
  451.  
  452.     // reject attempt to return buffers after the session is closed…
  453.     //    MacTCP has done it already (I think)
  454.  
  455.     if (hasSessionOpen) {
  456.         theRcvParam.csParam.receive.rdsPtr = itsRDS;
  457.         theRcvParam.csParam.receive.userDataPtr = (Ptr) this;
  458.     
  459.         DoSyncCall(TCPRcvBfrReturn, &theRcvParam);
  460.                                 // ignore errors — this is bad practice, but…
  461.     }
  462.  
  463. }
  464.  
  465.  
  466. /*______________________________________________________________________
  467. **
  468. ** Send
  469. **
  470. **    Send data on the TCP stream using the Write Data Structure (WDS) structure. The
  471. **    asynchronous completion routine can optionally dispose of the WDS and its associated data
  472. **    structures once the write operation is completed. If so, the buffers you provide must be
  473. **    expendable.
  474. **
  475. **        itsWDS (wdsEntry *):    write data structure (see MacTCP manual, p30)
  476. **        itsTimeOut (b_16):        command timeout value in seconds (0 = infinite)
  477. **        disposeWDS (Boolean):    dispose of WDS and data structures when completed
  478. **
  479. */
  480.  
  481. void CTCPStream::Send (wdsEntry *itsWDS, b_16 itsTimeOut, Boolean disposeWDS)
  482.  
  483. {
  484.     TCPiopb    theSendParam;
  485.     OSErr    theResult;
  486.  
  487.  
  488.     // ensure that at least one byte is being sent
  489.     
  490.     
  491.     if ((*itsWDS).length == 0)
  492.         return;
  493.     
  494.  
  495.     // fill in parms to send call
  496.     
  497.     theSendParam.csParam.send.ulpTimeoutValue = itsTimeOut;
  498.     theSendParam.csParam.send.ulpTimeoutAction = itsULPaction;
  499.     theSendParam.csParam.send.validityFlags = itsValidityFlag;
  500.     theSendParam.csParam.send.pushFlag = sendNextPush;
  501.     theSendParam.csParam.send.urgentFlag = sendNextUrgent;
  502.     theSendParam.csParam.send.wdsPtr = (Ptr) itsWDS;
  503.     theSendParam.csParam.send.userDataPtr = (Ptr) this;
  504.     
  505.     theSendParam.csParam.open.security = disposeWDS;
  506.                     //   ^^^^ this isn’t pretty, but it’s efficient
  507.  
  508.     sendNextPush = FALSE;
  509.     sendNextUrgent = 0;
  510.  
  511.  
  512.     // perform the call
  513.     
  514.     theResult = DoAsyncCall(TCPSend, &theSendParam);
  515.     if (theResult)
  516.         HandleTCPError(theResult, TCPSend);
  517. }
  518.  
  519.  
  520. /*______________________________________________________________________
  521. **
  522. ** Receive
  523. **
  524. **    Receive data and copy to a user buffer.
  525. **
  526. **        theData (Ptr):        receive buffer
  527. **        theDataSize (b_16):    size of receive buffer in bytes
  528. **        itsTimeOut (b_16):    command timeout value in seconds (0 = infinite)
  529. **
  530. */
  531.  
  532. void CTCPStream::Receive (Ptr theData, b_16 itsDataSize, b_16 itsTimeOut)
  533.  
  534. {
  535.     TCPiopb    theRcvParam;
  536.     OSErr    theResult;
  537.  
  538.     theRcvParam.csParam.receive.commandTimeoutValue = itsTimeOut;
  539.     theRcvParam.csParam.receive.rcvBuff = theData;
  540.     theRcvParam.csParam.receive.rcvBuffLen = (unsigned short) itsDataSize;
  541.     theRcvParam.csParam.receive.userDataPtr = (Ptr) this;
  542.     theRcvParam.csParam.open.userDataPtr = (Ptr) itsRcvBypassProc;
  543.                                         // hide the extra data in unused fields
  544.  
  545.     theResult = DoAsyncCall(TCPRcv, &theRcvParam);
  546.     if (theResult)
  547.         HandleTCPError(theResult, TCPRcv);
  548. }
  549.  
  550.  
  551. /*______________________________________________________________________
  552. **
  553. ** Status
  554. **
  555. **    Returns a large pile of information about the TCP connection.
  556. **
  557. **        theStatusBlock (TCPStatusPB *):    user buffer for TCP status info
  558. **
  559. */
  560.  
  561. void CTCPStream::Status (TCPStatusPB *theStatusBlock)
  562.  
  563. {
  564.     TCPiopb    theStatusParam;
  565.     short    i;
  566.     Ptr        p;
  567.  
  568.     DoSyncCall(TCPStatus, &theStatusParam);
  569.     BlockMove(&theStatusParam.csParam, theStatusBlock, 66);
  570.     if (theStatusParam.ioResult != noErr) {
  571.         i = 0;
  572.         p = (Ptr) theStatusBlock;
  573.         while (i++<66)
  574.             *(p++) = 0;
  575.     }
  576. }
  577.  
  578.  
  579. /*______________________________________________________________________
  580. **
  581. ** ConnectionState
  582. **
  583. **    Returns the current status of the MacTCP stream. For definitions of the state codes,
  584. **    see TCP reference manual, p56.
  585. **
  586. **        return (b_16):    status of TCP stream
  587. **
  588. */
  589.  
  590. b_16 CTCPStream::ConnectionState (void)
  591.  
  592. {
  593.     TCPStatusPB theStatusBlock;
  594.     
  595.     Status(&theStatusBlock);
  596.     return(theStatusBlock.connectionState);
  597. }
  598.  
  599.  
  600. //    —— specialized functions for sending data ——
  601.  
  602. /*______________________________________________________________________
  603. **
  604. ** SendChar
  605. **
  606. **    Send a single character to the TCP stream.
  607. **
  608. **        theChar (char):        the character to send
  609. **
  610. */
  611.  
  612. void CTCPStream::SendChar (char theChar)
  613.  
  614. {
  615.     SendBfrCpy(&theChar, 1);
  616. }
  617.  
  618.  
  619. /*______________________________________________________________________
  620. **
  621. ** SendCString
  622. **
  623. **    Send a C string to the TCP stream.
  624. **
  625. **        theString (char *):    the string to send
  626. **
  627. */
  628.  
  629. void CTCPStream::SendCString (char *theString)
  630.  
  631. {
  632.     SendBfrCpy(theString, cstrlen(theString));
  633. }
  634.  
  635.  
  636. /*______________________________________________________________________
  637. **
  638. ** SendPString
  639. **
  640. **    Send a Pascal string to the TCP stream.
  641. **
  642. **        theString (Str255):    the string to send
  643. **
  644. */
  645.  
  646. void CTCPStream::SendPString (ConstStr255Param theString)
  647.  
  648. {
  649.     SendBfrCpy((char *) theString + 1, theString[0]);
  650. }
  651.  
  652.  
  653. /*______________________________________________________________________
  654. **
  655. ** SendBfrCpy
  656. **
  657. **    Send a range of bytes to the TCP stream. Prepares a WDS for the Send method and copies
  658. **    the bytes from the caller’s buffer to a data buffer which can persist beyond the procedure
  659. **    or object which generated the data.
  660. **
  661. **        theData (Ptr):        the bytes to send
  662. **        theDataSize (b_16):    number of bytes to send
  663. **
  664. */
  665.  
  666. void CTCPStream::SendBfrCpy (Ptr theData, b_16 theDataSize)
  667.  
  668. {
  669.     wdsEntry    *itsWDS = NULL;
  670.     Ptr        itsNewBuffer = NULL;
  671.     
  672.  
  673.     // make sure there’s something to send
  674.  
  675.     if (theDataSize == 0)
  676.         return;
  677.     
  678.     TRY {
  679.     
  680.         // create the two buffers
  681.  
  682.         itsWDS = (wdsEntry *) NewPtr(8);            // WDS with room for one entry
  683.         itsNewBuffer = NewPtr(theDataSize);
  684.  
  685.  
  686.         // copy stuff to new buffer
  687.         
  688.         BlockMove(theData, itsNewBuffer, theDataSize);
  689.         (*itsWDS).length = theDataSize;
  690.         (*itsWDS).ptr = itsNewBuffer;
  691.         (*(++itsWDS)).length = 0;
  692.         --itsWDS;
  693.  
  694.  
  695.         // send data, using default timeout value
  696.         
  697.         Send(itsWDS, itsULPtimeout, TRUE);
  698.  
  699.     }
  700.     
  701.     CATCH {
  702.         ForgetPtr(itsWDS);
  703.         ForgetPtr(itsNewBuffer);
  704.     }
  705.     ENDTRY;
  706.  
  707. }
  708.  
  709.  
  710. /*______________________________________________________________________
  711. **
  712. ** SendBfrNoCpy
  713. **
  714. **    Send a range of bytes to the TCP stream. Prepares a WDS for the Send method. Does not
  715. **    copy the bytes.
  716. **
  717. **        theData (Ptr):                the bytes to send
  718. **        theDataSize (b_16):            number of bytes to send
  719. **        disposeWhenDone (Boolean):    dispose of the buffer when completed — set to TRUE
  720. **                                    only if this pointer was allocated as a pointer,
  721. **                                    not a handle deref
  722. **
  723. */
  724.  
  725. void CTCPStream::SendBfrNoCpy (Ptr theData, b_16 theDataSize, Boolean disposeWhenDone)
  726.  
  727. {
  728.     wdsEntry *itsWDS = NULL;
  729.     
  730.  
  731.     // make sure there’s something to send
  732.  
  733.     if (theDataSize == 0)
  734.         return;
  735.     
  736.     TRY {
  737.  
  738.         // create the WDS buffer & fill it in
  739.  
  740.         itsWDS = (wdsEntry *) NewPtr(8);            // WDS with room for one entry
  741.         
  742.         (*itsWDS).length = theDataSize;
  743.         (*itsWDS).ptr = theData;
  744.         (*(++itsWDS)).length = 0;
  745.         --itsWDS;
  746.  
  747.  
  748.         // send data, using default timeout value
  749.         
  750.         Send(itsWDS, itsULPtimeout, disposeWhenDone);
  751.     }
  752.     
  753.     CATCH {
  754.         ForgetPtr(itsWDS);
  755.     }
  756.     ENDTRY;
  757.  
  758. }
  759.  
  760.  
  761. /*______________________________________________________________________
  762. **
  763. ** SetNextPush
  764. **
  765. **    Use before any send-data command to make sure that data is sent with the “push” flag set.
  766. **
  767. */
  768.  
  769. void CTCPStream::SetNextPush (void)
  770.  
  771. {
  772.     sendNextPush = TRUE;
  773. }
  774.  
  775.  
  776. /*______________________________________________________________________
  777. **
  778. ** SetNextUrgent
  779. **
  780. **    Use before any send-data command to make sure that data is sent with the “urgent”
  781. **    flag set.
  782. **
  783. **        useRFC793 (Boolean):    TRUE to use the non-compliant method in RFC 793
  784. **
  785. */
  786.  
  787. void CTCPStream::SetNextUrgent (Boolean useRFC793)
  788.  
  789. {
  790.     sendNextUrgent = (useRFC793 ? 2 : 1);
  791. }
  792.  
  793.  
  794. //    —— notification routines
  795.  
  796. /*______________________________________________________________________
  797. **
  798. ** HandleClosed
  799. **
  800. **    Respond to notification that the session has closed.
  801. **
  802. */
  803.  
  804. void CTCPStream::HandleClosed (void)
  805.  
  806. {
  807.     BroadcastSafeChange(tcpStreamClosed, NULL);
  808. }
  809.  
  810.  
  811. /*______________________________________________________________________
  812. **
  813. ** HandleClosing
  814. **
  815. **    Respond to notification that the session is being closed.
  816. **
  817. **        remoteClosing (Boolean):    TRUE if close initiated by remote host
  818. **
  819. */
  820.  
  821. void CTCPStream::HandleClosing (Boolean remoteClosing)
  822.  
  823. {
  824.     BroadcastSafeChange(tcpStreamClosing, (void *) remoteClosing);
  825. }
  826.  
  827.  
  828. /*______________________________________________________________________
  829. **
  830. ** HandleDataArrived (should only be called by CTCPAsyncCall::Dispatch)
  831. **
  832. **    Process notification that data has arrived.
  833. **
  834. **        theData (Ptr):        pointer to the data
  835. **        theDataSize (b_16):    size of data
  836. **        isUrgent (Boolean):    TRUE if remote host signalled TCP urgent data
  837. **
  838. */
  839.  
  840. void CTCPStream::HandleDataArrived (Ptr theData, b_16 theDataSize, Boolean isUrgent)
  841.  
  842. {
  843.     DataArrivedInfo    info;
  844.  
  845.     info.theData = theData;
  846.     info.theDataSize = theDataSize;
  847.     info.isUrgent = isUrgent;
  848.  
  849.     BroadcastChange(tcpStreamDataArrived, &info);
  850. }
  851.  
  852.  
  853. /*______________________________________________________________________
  854. **
  855. ** HandleDataSent
  856. **
  857. **    Respond to notification that data has been successfully sent.
  858. **
  859. **        WDSPtr (wdsEntry *):    the WDS structure for the data that was sent
  860. **
  861. */
  862.  
  863. void CTCPStream::HandleDataSent (wdsEntry *WDSPtr)
  864.  
  865. {
  866.     BroadcastChange(tcpStreamDataSent, WDSPtr);
  867. }
  868.  
  869.  
  870. /*______________________________________________________________________
  871. **
  872. ** HandleICMP
  873. **
  874. **    Respond to an ICMP message which was received.
  875. **
  876. **        icmpMsg (struct ICMPReport *):    the ICMP message report
  877. **
  878. */
  879.  
  880. void CTCPStream::HandleICMP (struct ICMPReport *icmpMsg)
  881.  
  882. {
  883.     BroadcastChange(tcpStreamICMP, icmpMsg);
  884. }
  885.  
  886.  
  887. /*______________________________________________________________________
  888. **
  889. ** HandleOpened
  890. **
  891. **    Respond to successful completion of a TCPPassiveOpen or TCPActiveOpen command.
  892. **
  893. */
  894.  
  895. void CTCPStream::HandleOpened (void)
  896.  
  897. {
  898.     short i;
  899.  
  900.  
  901.     // let everyone know we’ve got an active session
  902.  
  903.     hasSessionOpen = TRUE;
  904.     pendingOpen = FALSE;
  905.     BroadcastChange(tcpStreamOpened, NULL);
  906.  
  907.  
  908.     // issue all the auto-receive commands needed
  909.  
  910.     for (i=1; i<=itsAutoReceiveNum; i++)
  911.         IssueAutoReceive();
  912.  
  913. }
  914.  
  915.  
  916. /*______________________________________________________________________
  917. **
  918. ** HandleOpenFailed
  919. **
  920. **    Respond to notification that a TCPOpen command failed.
  921. **
  922. **        theResultCode (OSErr):    the reason for failure
  923. **
  924. */
  925.  
  926. void CTCPStream::HandleOpenFailed (OSErr theResultCode)
  927.  
  928. {
  929.     hasSessionOpen = FALSE;
  930.     pendingOpen = FALSE;
  931.  
  932.     BroadcastSafeChange(tcpStreamOpenFailed, (void *) theResultCode);
  933. }
  934.  
  935.  
  936. /*______________________________________________________________________
  937. **
  938. ** HandleSendFailed
  939. **
  940. **    Respond to failure to send data. The WDS is returned so the data may be re-sent. After
  941. **    the dependents are notified, this method frees the WDS and the data buffers.
  942. **
  943. **        WDSPtr (wdsEntry *):    the WDS structure
  944. **        theResultCode (OSErr):    the reason for failure
  945. **
  946. */
  947.  
  948. void CTCPStream::HandleSendFailed (wdsEntry    *WDSPtr, OSErr theResultCode)
  949.  
  950. {
  951.     SendFailedInfo    info;
  952.     wdsEntry        *theDisposePtr = WDSPtr;
  953.  
  954.  
  955.     // package up the information for dependent objects
  956.     
  957.     info.WDSPtr = WDSPtr;
  958.     info.theResultCode = theResultCode;
  959.     BroadcastSafeChange(tcpStreamSendFailed, &info);
  960.     
  961.     
  962.     // free the buffers holding the unsent data
  963.     
  964.     while ((*theDisposePtr).length) {
  965.         ForgetPtr((*theDisposePtr).ptr);
  966.         theDisposePtr++;
  967.     }
  968.     ForgetPtr(WDSPtr);
  969.     
  970. }
  971.  
  972.  
  973. /*______________________________________________________________________
  974. **
  975. ** HandleTCPError
  976. **
  977. **    Respond to failure of a TCP command that was not expected. Sends notification to
  978. **    dependent objects.
  979. **
  980. **        theResultCode (OSErr):    the result code
  981. **        theCsCode (short):        the TCP command number that failed
  982. **
  983. */
  984.  
  985. void CTCPStream::HandleTCPError (OSErr theResultCode, short theCsCode)
  986.  
  987. {
  988.     TCPErrorInfo    info;
  989.     
  990.     info.theResultCode = theResultCode;
  991.     info.theCsCode = theCsCode;
  992.     BroadcastSafeChange(tcpStreamTCPError, &info);
  993. }
  994.  
  995.  
  996. /*______________________________________________________________________
  997. **
  998. ** HandleTerminated
  999. **
  1000. **    Respond to session termination event.
  1001. **
  1002. **        terminReason (b_16):    the termination code
  1003. **
  1004. */
  1005.  
  1006. void CTCPStream::HandleTerminated (b_16 terminReason)
  1007.  
  1008. {
  1009.     TerminatedInfo    info;
  1010.  
  1011.     info.terminReason = terminReason;
  1012.     info.aboutToDispose = pendingDispose || disposeOnTerminate;
  1013.     BroadcastSafeChange(tcpStreamTerminated, &info);
  1014. }
  1015.  
  1016.  
  1017. /*______________________________________________________________________
  1018. **
  1019. ** HandleTimeout
  1020. **
  1021. **    Respond to a ULP timeout event (remote TCP failed to respond in time). This method is
  1022. **    only called if the ULP timeout action is set to abort & notify.
  1023. **
  1024. */
  1025.  
  1026. void CTCPStream::HandleTimeout (void)
  1027.  
  1028. {
  1029.     BroadcastSafeChange(tcpStreamTimeout, NULL);
  1030. }
  1031.  
  1032.  
  1033. /*______________________________________________________________________
  1034. **
  1035. ** HandleUnexpectedData
  1036. **
  1037. **    Respond to notification that data arrived without a receive command.
  1038. **
  1039. */
  1040.  
  1041. void CTCPStream::HandleUnexpectedData (void)
  1042.  
  1043. {
  1044.     BroadcastChange(tcpStreamUnexpectedData, NULL);
  1045. }
  1046.  
  1047.  
  1048. /*______________________________________________________________________
  1049. **
  1050. ** HandleUrgentBegin
  1051. **
  1052. **    Respond to notification that urgent data is arriving.
  1053. **
  1054. */
  1055.  
  1056. void CTCPStream::HandleUrgentBegin (void)
  1057.  
  1058. {
  1059.     BroadcastChange(tcpStreamUrgentBegin, NULL);
  1060. }
  1061.  
  1062.  
  1063. //    —— set configuration ——
  1064.  
  1065. /*______________________________________________________________________
  1066. **
  1067. ** InstallRcvBypass
  1068. **
  1069. **    Install a receive “bypass” routine. This routine may be used to accelerate the processing
  1070. **    of arriving data by bypassing several method dispatches.
  1071. **
  1072. **    A bypass routine is called by the CTCPAsyncCall::Dispatch routine for each block of data.
  1073. **    This call is made in place of the call to CTCPStream::HandleDataArrived. The routine
  1074. **    should make a class-specific call to your object’s routine for processing data with the
  1075. **    same parameters provided to it. (See example below.)
  1076. **
  1077. **        typedef void (*RcvBypassProc) (CDirectorOwner *theObject, Ptr theData,
  1078. **                              b_16 theDataSize, Boolean isUrgent);
  1079. **
  1080. **        {
  1081. **            ((CYourClass *) theObject)->HandleDataArrived(…);
  1082. **        }
  1083. **
  1084. **
  1085. **    input (to InstallRcvBypass):
  1086. **        aRcvBypassProc (RcvBypassProc):    the receive bypass procedure for this stream
  1087. **
  1088. */
  1089.  
  1090.     struct BypassTargetRec {
  1091.         CObject            *target;
  1092.         RcvBypassProc        proc;
  1093.     };
  1094.  
  1095. void CTCPStream::InstallRcvBypass (CObject *whoToCall, RcvBypassProc aRcvBypassProc)
  1096.  
  1097. {
  1098.     struct BypassTargetRec s;
  1099.     
  1100.     s.target = itsRcvBypassTarget = whoToCall;
  1101.     s.proc = itsRcvBypassProc = aRcvBypassProc;
  1102.     itsAsyncCalls->DoForEach1(&GiveBypassToAsyncCall, (long) &s);
  1103. }
  1104.  
  1105.     // private static method for iteration
  1106.     
  1107.     void CTCPStream::GiveBypassToAsyncCall (CObject *theObject, long param)
  1108.     {
  1109.         ((CTCPAsyncCall *) theObject)->
  1110.                 SetRcvBypassProc(((struct BypassTargetRec *) param)->target,
  1111.                                 ((struct BypassTargetRec *) param)->proc);
  1112.     }
  1113.  
  1114.  
  1115. /*______________________________________________________________________
  1116. **
  1117. ** SetULPTimeoutValue
  1118. **
  1119. **    Sets the ULP timeout value. The value given here applies to all subsequent open and
  1120. **    send calls.
  1121. **
  1122. **        ulpTimeoutValue (b_16):    timeout value (seconds, 0 = infinite)
  1123. **
  1124. */
  1125.  
  1126. void CTCPStream::SetULPTimeoutValue (b_16 ulpTimeoutValue)
  1127.  
  1128. {
  1129.     itsULPtimeout = ulpTimeoutValue;
  1130.     itsValidityFlag |= timeoutValue;
  1131. }
  1132.  
  1133.  
  1134. /*______________________________________________________________________
  1135. **
  1136. ** SetULPTimeoutAction
  1137. **
  1138. **    Sets the ULP timeout value. This call is only useful when a connection has not been opened
  1139. **    on this stream. (Otherwise, the value applies to subsequent connections on the same
  1140. **    stream.)
  1141. **
  1142. **        ulpTimeoutAction (b_16):    ULP timeout action (0 = report, nonzero = abort)
  1143. **
  1144. */
  1145.  
  1146. void CTCPStream::SetULPTimeoutAction (b_16 ulpTimeoutAction)
  1147.  
  1148. {
  1149.     itsULPaction = ulpTimeoutAction;
  1150.     itsValidityFlag |= timeoutAction;
  1151. }
  1152.  
  1153.  
  1154. /*______________________________________________________________________
  1155. **
  1156. ** SetCommandTimeout
  1157. **
  1158. **    Sets the command timeout value. This call is only useful when a connection has not been
  1159. **    opened on this stream. (Otherwise, the value applies to subsequent connections on the
  1160. **    same stream.)
  1161. **
  1162. **        cmdTimeoutValue (b_16):    command timeout value in seconds
  1163. **
  1164. */
  1165.  
  1166. void CTCPStream::SetCommandTimeout (b_16 cmdTimeoutValue)
  1167.  
  1168. {
  1169.     itsCommandTimeoutValue = cmdTimeoutValue;
  1170. }
  1171.  
  1172.  
  1173. /*______________________________________________________________________
  1174. **
  1175. ** SetTypeOfService
  1176. **
  1177. **    Sets the type of service flag. This call is only useful when a connection has not been
  1178. **    opened on this stream. (Otherwise, the value applies to subsequent connections on the
  1179. **    same stream.)
  1180. **
  1181. **        newTosFlag (b_16):    type-of-service value
  1182. **
  1183. */
  1184.  
  1185. void CTCPStream::SetTypeOfService (b_16 newTosFlag)
  1186.  
  1187. {
  1188.     itsTosFlags = newTosFlag;
  1189.     itsValidityFlag |= typeOfService;
  1190. }
  1191.  
  1192.  
  1193. /*______________________________________________________________________
  1194. **
  1195. ** SetPrecedence
  1196. **
  1197. **    Sets the precedence flag. This call is only useful when a connection has not been opened on
  1198. **    this stream. (Otherwise, the value applies to subsequent connections on the same stream.)
  1199. **
  1200. **        newPrecedence (b_16):    the precedence flag
  1201. **
  1202. */
  1203.  
  1204. void CTCPStream::SetPrecedence (b_16 newPrecedence)
  1205.  
  1206. {
  1207.     itsPrecedence = newPrecedence;
  1208.     itsValidityFlag |= precedence;
  1209. }
  1210.  
  1211.  
  1212. /*______________________________________________________________________
  1213. **
  1214. ** SetDontFrag
  1215. **
  1216. **    Sets the don’t fragment flag. This call is only useful when a connection has not been
  1217. **    opened on this stream. (Otherwise, the value applies to subsequent connections on the
  1218. **    same stream.)
  1219. **
  1220. **        newDontFrag (b_16):    TRUE to prevent fragmentation of data segments
  1221. **
  1222. */
  1223.  
  1224. void CTCPStream::SetDontFrag (b_16 newDontFrag)
  1225.  
  1226. {
  1227.     itsDontFrag = newDontFrag;
  1228. }
  1229.  
  1230.  
  1231. /*______________________________________________________________________
  1232. **
  1233. ** SetTimeToLive
  1234. **
  1235. **    Sets the ULP timeout value. This call is only useful when a connection has not been
  1236. **    opened on this stream. (Otherwise, the value applies to subsequent connections on the
  1237. **    same stream.)
  1238. **
  1239. **        newTimeToLive (b_16):    time to live value (seconds)
  1240. **
  1241. */
  1242.  
  1243. void CTCPStream::SetTimeToLive (b_16 newTimeToLive)
  1244.  
  1245. {
  1246.     itsTimeToLive = newTimeToLive;
  1247. }
  1248.  
  1249.  
  1250. /*______________________________________________________________________
  1251. **
  1252. ** SetSecurity
  1253. **
  1254. **    Sets the security flag. This call is only useful when a connection has not been opened on
  1255. **    this stream. (Otherwise, the value applies to subsequent connections on the same stream.)
  1256. **
  1257. **        newSecurity (b_16): security flag value
  1258. **
  1259. */
  1260.  
  1261. void CTCPStream::SetSecurity (b_16 newSecurity)
  1262.  
  1263. {
  1264.     itsSecurity = newSecurity;
  1265. }
  1266.  
  1267.  
  1268. /*______________________________________________________________________
  1269. **
  1270. ** SetIPOptions
  1271. **
  1272. **    Sets the IP options. This call is only useful when a connection has not been opened on this
  1273. **    stream. (Otherwise, the value applies to subsequent connections on the same stream.)
  1274. **
  1275. **        newOptionsSize (b_16):        number of bytes in IP options string
  1276. **        newOptions (IPOptionString *):    the IP options bytes
  1277. **
  1278. */
  1279.  
  1280. void CTCPStream::SetIPOptions (b_16 newOptionsSize, IPOptionString *newOptions)
  1281.  
  1282. {
  1283.     Boolean    wasLocked = this->Lock(TRUE);
  1284.     
  1285.     itsOptionCnt = newOptionsSize;
  1286.     BlockMove(newOptions, &itsOptions, IPOptionStringSize);
  1287.     this->Lock(wasLocked);
  1288. }
  1289.  
  1290.  
  1291. //    —— TCP urgent mode ——
  1292.  
  1293. /*______________________________________________________________________
  1294. **
  1295. ** RcvUrgentStatus
  1296. **
  1297. **    Return urgent mode status of stream.
  1298. **
  1299. **        return (Boolean):    TRUE if stream is receiving urgent data
  1300. **
  1301. */
  1302.  
  1303. Boolean CTCPStream::RcvUrgentStatus (void)
  1304.  
  1305. {
  1306.     return(rcvUrgent);
  1307. }
  1308.  
  1309.  
  1310. /*______________________________________________________________________
  1311. **
  1312. ** RcvUrgentBegin (should only be called by TCP completion routine)
  1313. **
  1314. **    Signal beginning of urgent data.
  1315. **
  1316. */
  1317.  
  1318. void CTCPStream::RcvUrgentBegin (void)
  1319.  
  1320. {
  1321.     rcvUrgent = TRUE;
  1322. }
  1323.  
  1324.  
  1325. /*______________________________________________________________________
  1326. **
  1327. ** RcvUrgentMark (should only be called by TCP completion routine)
  1328. **
  1329. **    Signal end of urgent data.
  1330. **
  1331. */
  1332.  
  1333. void CTCPStream::RcvUrgentMark (void)
  1334.  
  1335. {
  1336.     rcvUrgent = FALSE;
  1337. }
  1338.  
  1339.  
  1340. //    —— protected methods to issue TCP calls ——
  1341.  
  1342. /*______________________________________________________________________
  1343. **
  1344. ** DoAsyncCall (protected method)
  1345. **
  1346. **    Creates a CTCPAsyncCall object and uses it to execute a TCP Device Manager call
  1347. **    asynchronously. Does not wait for completion. Fails if not enough memory to
  1348. **    create call object.
  1349. **
  1350. **        theCsCode (b_16):                TCP operation code
  1351. **        theParamBlockPtr (TCPiopb *):        parameter block for TCP call
  1352. **
  1353. **        return (OSErr):                    result code (+1 is not returned)
  1354. **
  1355. */
  1356.  
  1357. OSErr CTCPStream::DoAsyncCall (b_16 theCsCode, TCPiopb *theParamBlockPtr)
  1358.  
  1359. {
  1360.     OSErr        theResult;
  1361.     CTCPAsyncCall    *theCall;
  1362.  
  1363.  
  1364.     // make sure a stream was opened
  1365.     
  1366.     if (macTCPStream)
  1367.         (*theParamBlockPtr).tcpStream = (StreamPtr) macTCPStream;
  1368.     else
  1369.         return (invalidStreamPtr);
  1370.  
  1371.  
  1372.     // create call object
  1373.     
  1374.     theCall = new (CTCPAsyncCall);
  1375.     theCall->ITCPAsyncCall(this);
  1376.     if (theCsCode == TCPNoCopyRcv)
  1377.         theCall->SetRcvBypassProc(itsRcvBypassTarget, itsRcvBypassProc);
  1378.     theResult = theCall->DoAsyncCall(theCsCode, theParamBlockPtr);
  1379.     if (theResult == inProgress)
  1380.         itsAsyncCalls->Add(theCall);
  1381.     return ((theResult == inProgress) ? noErr : theResult);
  1382. }
  1383.  
  1384.  
  1385. /*______________________________________________________________________
  1386. **
  1387. ** DoSyncCall (protected method)
  1388. **
  1389. **    Fills in the standard parameters for a TCP Device Manager call and executes the call.
  1390. **    Waits for completion of the call.
  1391. **
  1392. **        theCsCode (b_16):                TCP operation code
  1393. **        theParamBlockPtr (TCPiopb *):        parameter block for TCP call
  1394. **
  1395. **        return (OSErr):                    result code (+1 is not returned)
  1396. **
  1397. */
  1398.  
  1399. OSErr CTCPStream::DoSyncCall (b_16 theCsCode, TCPiopb *theParamBlockPtr)
  1400.  
  1401. {
  1402.  
  1403.     // make sure a stream was opened
  1404.     
  1405.     if (macTCPStream)
  1406.         (*theParamBlockPtr).tcpStream = (StreamPtr) macTCPStream;
  1407.     else
  1408.         return (invalidStreamPtr);
  1409.  
  1410.  
  1411.     // perform the call
  1412.     
  1413.     (*theParamBlockPtr).ioCompletion = (TCPIOCompletionProc) NULL;
  1414.     (*theParamBlockPtr).ioCRefNum = gTCPDriver->GetTCPRefNum();
  1415.     (*theParamBlockPtr).csCode = theCsCode;
  1416.     PBControlSync((ParmBlkPtr) theParamBlockPtr);
  1417.     return ((*theParamBlockPtr).ioResult);
  1418. }
  1419.  
  1420.  
  1421. //    —— auto-receive processing ——
  1422.  
  1423. /*______________________________________________________________________
  1424. **
  1425. ** IssueAutoReceive (protected method)
  1426. **
  1427. **    Issue a NoCopyRcv command to grab the next batch of data. Does nothing if auto-receive
  1428. **    is not enabled.
  1429. **
  1430. */
  1431.  
  1432. void CTCPStream::IssueAutoReceive (void)
  1433.  
  1434. {
  1435.     Ptr    newRDS;                        // the new RDS pointer
  1436.  
  1437.  
  1438.     // create a new RDS with room for # of entries requested & send it to TCP
  1439.     
  1440.     if (hasSessionOpen && itsAutoReceiveSize) {
  1441.         FailNIL(newRDS = NewPtr((itsAutoReceiveSize*6)+2));
  1442.         NoCopyRcv((rdsEntry *) newRDS, itsAutoReceiveSize, 0);
  1443.     }
  1444. }
  1445.  
  1446.  
  1447. //    —— modified collaborator mechanism ——
  1448.  
  1449. /*______________________________________________________________________
  1450. **
  1451. ** BroadcastSafeChange (protected method)
  1452. **
  1453. **    Same as CCollaborator::BroadcastChange, except it iterates over a copy of the
  1454. **    dependents list. This allows the dependents to dispose of themselves in the iteration
  1455. **    routine without wreaking havoc.
  1456. **
  1457. **        reason (long):    the reason code to broadcast
  1458. **        info (void *):    additional information to pass along
  1459. **
  1460. */
  1461.  
  1462.     typedef struct tUpdateInfo {
  1463.         CCollaborator    *provider;
  1464.         long            reason;
  1465.         void            *info;
  1466.     } tUpdateInfo;
  1467.  
  1468.  
  1469. void CTCPStream::BroadcastSafeChange (long reason, void *info)
  1470.  
  1471. {
  1472.     tUpdateInfo    updateInfo;
  1473.     long            nullInfo;
  1474.     CList            *itsDependentsCopy;
  1475.  
  1476.  
  1477.     if (itsDependents) {
  1478.     
  1479.         // clone the dependents list
  1480.         
  1481.         itsDependentsCopy = (CList *) (itsDependents->Copy());
  1482.  
  1483.  
  1484.         // create a valid dereference for NULL info
  1485.  
  1486.         if (!info) {
  1487.             nullInfo = 0L;
  1488.             info = &nullInfo;
  1489.         }
  1490.  
  1491.  
  1492.         // iterate over the list
  1493.         
  1494.         updateInfo.provider = this;
  1495.         updateInfo.reason = reason;
  1496.         updateInfo.info = info;
  1497.         itsDependentsCopy->DoForEach1(CCollaborator::Dependent_Update, 
  1498.                                     (long) &updateInfo);
  1499.         ForgetObject(itsDependentsCopy);
  1500.     }
  1501.  
  1502. }
  1503.  
  1504.  
  1505. //    —— delayed-processing routines: respond to interrupt notifications
  1506.  
  1507. /*______________________________________________________________________
  1508. **
  1509. ** ProcessNotify
  1510. **
  1511. **    Respond to notifications received by the ASR during interrupt time. This routine is free
  1512. **    of interrupt-level constraints.
  1513. **
  1514. */
  1515.  
  1516. void CTCPStream::ProcessNotify (void)
  1517.  
  1518. {
  1519.     // no longer in notify queue
  1520.     
  1521.     pendingNotify = FALSE;
  1522.     
  1523.     
  1524.     // if terminated, inform the stream owner & dispose (if appropriate)
  1525.     //    clear all other notifications (they no longer apply)
  1526.  
  1527.     if (notifTerminate) {
  1528.         HandleTerminated(notifTermReason);
  1529.         hasSessionOpen = pendingOpen = pendingClose = 
  1530.             remoteClose = pendingAbort = notifClosing = notifTimeout =
  1531.             notifDataArrived = notifUrgent = FALSE;
  1532.         receivedClose = receivedTerminate = TRUE;
  1533.         if (disposeOnTerminate)
  1534.             PostponeDispose();
  1535.     }
  1536.  
  1537.  
  1538.     // if closed, inform stream owner, wait for termination before disposing (if appropriate)
  1539.  
  1540.     if (notifClosing) {
  1541.         HandleClosing(remoteClose);
  1542.         receivedClose = TRUE;
  1543.         notifClosing = FALSE;
  1544.         if (disposeOnTerminate)
  1545.             PostponeDispose();
  1546.     }
  1547.  
  1548.  
  1549.     // if urgent notification, flag beginning of urgent data
  1550.  
  1551.     if (notifUrgent) {
  1552.         if (!rcvUrgent) {
  1553.             RcvUrgentBegin();
  1554.             HandleUrgentBegin();
  1555.         }
  1556.         notifUrgent = FALSE;
  1557.     }
  1558.  
  1559.  
  1560.     // tell stream owner about other notifications, TurboTCP doesn’t respond to these
  1561.  
  1562.     if (notifTimeout) {
  1563.         HandleTimeout();
  1564.         notifTimeout = FALSE;
  1565.     }
  1566.     
  1567.     if (notifDataArrived) {
  1568.         HandleUnexpectedData();
  1569.         notifDataArrived = FALSE;
  1570.     }
  1571.     
  1572.     if (notifICMP) {
  1573.         HandleICMP(¬ifICMPreport);
  1574.         notifICMP = FALSE;
  1575.     }
  1576.  
  1577. }
  1578.  
  1579.  
  1580. /*______________________________________________________________________
  1581. **
  1582. ** ProcessAsyncCompletion
  1583. **
  1584. **    Respond to the completion of an asynchronous call. Removes the async call object from
  1585. **    the list of outstanding calls.
  1586. **
  1587. **        theCall (CTCPAsyncCall *):    the call which was completed
  1588. **
  1589. */
  1590.  
  1591. void CTCPStream::ProcessAsyncCompletion (CTCPAsyncCall *theCall)
  1592.  
  1593. {
  1594.     itsAsyncCalls->CCluster::Remove(theCall);
  1595. }
  1596.  
  1597.  
  1598. /***********************************************************************
  1599. ************************************************************************
  1600. **
  1601. **    INTERRUPT-LEVEL routines follow. These routines cannot make memory allocations, cannot make
  1602. **    synchronous TCP calls, and cannot use the Think C profiler.
  1603. **
  1604. */
  1605.  
  1606. #pragma options(!profile)
  1607.  
  1608.  
  1609. /*______________________________________________________________________
  1610. **
  1611. ** PostponeDispose
  1612. **
  1613. **    Add this stream object to the delayed disposal queue. This routine may be called during
  1614. **    an interrupt.
  1615. **
  1616. */
  1617.  
  1618. void CTCPStream::PostponeDispose (void)
  1619.  
  1620. {
  1621.     if (pendingDispose)                            // ignore this if we’re already in disposal queue
  1622.         return;
  1623.     pendingDispose = TRUE;
  1624.     disposeOnTerminate = TRUE;
  1625.     Enqueue((QElemPtr) &qDisposeEntry, &(gTCPDriver->asyncQueue));
  1626. }
  1627.  
  1628.  
  1629. /*______________________________________________________________________
  1630. **
  1631. ** PostponeNotify (protected method)
  1632. **
  1633. **    The asynchronous notification routine (ASR). Receives notification of events for all TCP
  1634. **    streams. Dispatches the notification to the proper method of the CTCPStream object. This
  1635. **    routine is installed for all TCP streams created by the CTCPStream object.
  1636. **
  1637. **    This method merely logs the kind of notification and adds this stream to the list of streams
  1638. **    to be processed next time through the event loop.
  1639. **
  1640. **        eventCode (b_16):                event code (see MacTCP manual, p37)
  1641. **        terminReason (b_16):            reason for termination (if applicable)
  1642. **        icmpMsg (structICMPReport *):    ICMP report (if applicable)
  1643. **
  1644. */
  1645.  
  1646. void CTCPStream::PostponeNotify (b_16 eventCode, b_16 terminReason, struct ICMPReport *icmpMsg)
  1647.  
  1648. {
  1649.  
  1650.     // reject notifications for unexpected data if auto-receiving
  1651.     
  1652.     if ((itsAutoReceiveSize > 0) && (eventCode == TCPDataArrival))
  1653.         return;
  1654.  
  1655.  
  1656.     // install this stream in asynchronous events queue
  1657.     //    CTCPDriver::ProcessNetEvents will pick it up later
  1658.  
  1659.     if (!pendingNotify) {
  1660.         Enqueue((QElemPtr) &qNotifyEntry, &(gTCPDriver->asyncQueue));
  1661.         pendingNotify = TRUE;
  1662.     }
  1663.  
  1664.  
  1665.     // record the event type
  1666.  
  1667.     switch (eventCode) {
  1668.         case TCPClosing:
  1669.             remoteClose = remoteClose || !pendingClose;
  1670.             notifClosing = pendingClose = TRUE;
  1671.             break;
  1672.  
  1673.         case TCPULPTimeout:
  1674.             notifTimeout = TRUE;
  1675.             break;
  1676.  
  1677.         case TCPTerminate:
  1678.             notifTerminate = TRUE;
  1679.             notifTermReason = terminReason;
  1680.             break;
  1681.  
  1682.         case TCPDataArrival:
  1683.             notifDataArrived = TRUE;
  1684.             break;
  1685.  
  1686.         case TCPUrgent:
  1687.             notifUrgent = TRUE;
  1688.             break;
  1689.  
  1690.         case TCPICMPReceived:
  1691.             notifICMP = TRUE;
  1692.             BlockMove(icmpMsg, ¬ifICMPreport, 24);
  1693.             break;
  1694.     }
  1695.  
  1696. }
  1697.  
  1698.  
  1699. /*______________________________________________________________________
  1700. **
  1701. ** NotifyProc (static protected method)
  1702. **
  1703. **    The asynchronous notification routine (ASR). This static method just decodes the
  1704. **    userDataPtr and calls PostponeNotify for the object named. This routine is the standard
  1705. **    ASR for all TCP streams created by the CTCPStream object.
  1706. **
  1707. **        tcpStream (StreamPtr):    the TCP stream in question
  1708. **        eventCode (short):        TCP event code (see MacTCP Dev guide, p37)
  1709. **        userDataPtr (Ptr):        user data pointer (in this case, the CTCPStream)
  1710. **        terminReason (short):    reason for termination (see MacTCP Dev guide, p37)
  1711. **        icmpMsg (…):            ICMP report (if applicable)
  1712. **
  1713. */
  1714.  
  1715. pascal void CTCPStream::NotifyProc (StreamPtr tcpStream, unsigned short eventCode,
  1716.                                 Ptr userDataPtr, unsigned short terminReason,
  1717.                                 struct ICMPReport *icmpMsg)
  1718.  
  1719. {
  1720.     CTCPStream *theTCPStream = (CTCPStream *) userDataPtr;
  1721.     theTCPStream->PostponeNotify(eventCode, terminReason, icmpMsg);
  1722. }
  1723.